const router = require('koa-router')()
const crypto = require('crypto')
const superagent = require('superagent')
const userLogin = require('../components/login')
const infoQuery = require('../components/infoQuery')
const cheerio = require('cheerio')
const db = require('../components/dbOption')
const { agent } = require('superagent')


const encrypt = function (str) {
  const md5 = crypto.createHash('md5')
  return md5.update(str).digest('hex')

}


const AgentMap = new Map()



/**
 * 生成指定长度随机字符串,默认28位
 * @param {*} len 
 */
function randomStr(len) {
  len = len || 28;
  var chars = 'ABCDEFGHIJKMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz0123456789';
  var maxPos = chars.length;
  var str = '';
  for (i = 0; i < len; i++) {
    str += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return str;
}

async function isLogin(uid) {

  let user = AgentMap.get(uid)
  let loginStatus = []
  if (user) {
    // 测试ehall登陆状态
    let agent = user.ehall
    await agent.get(`https://ehall.ecut.edu.cn/jsonp/userDesktopInfo.json?type=&_=${Date.now()}`).redirects(0).then(res => {
      console.log(res.statusCode)
      if (res.statusCode != 200) loginStatus.push('ehall')
    })
    agent = user.webvpn
    await agent.get('https://webvpn.ecut.edu.cn/').redirects(0).then(res => {
      console.log(res.statusCode)
      if (res.statusCode != 200) loginStatus.push('webvpn')
    })
  } else {
    loginStatus = ['ehall', 'webvpn']
  }

  return loginStatus

}


router.prefix('/main')




/**
 * @description 主函数，负责接收连接根据每个连接创建对应路由，以维持不同会话
 */
router.get('/', async function (ctx, next) {
  let { stu, passwd } = ctx.request.query

  let webvpnAgent = await userLogin.webvpnLogin(stu, passwd)
  let ehallAgent = await userLogin.ehallLogin(stu, passwd)

  let salt = randomStr(16)
  let uid = encrypt(stu + passwd + salt)

  //判断登陆是否成功
  if (ehallAgent !== false && webvpnAgent !== false) {
    let stuInfo = await db.queryStuInfoBySno(stu)
    stuInfo = Array.from(stuInfo)
    // console.log(stuInfo.length)
    // 判断用户是否已经登陆过
    if (stuInfo.length <= 0) {
      // 用户从未登陆过小程序

      // 数据插入数据库
      let res = await infoQuery.getStuInfo(ehallAgent)
      res.uid = uid
      res.loginTime = Date.now()
      db.insertStuInfo(res)
    } else {
      // 已经登陆过
      uid = stuInfo[0].uid
      db.updateLoginTime(uid, Date.now())
    }
    AgentMap.set(uid, { stu: stu, ehall: ehallAgent, webvpn: webvpnAgent })
    ctx.body = {
      code: 200,
      msg: 'success',
      data: {
        uid
      }
    }

  } else {
    // 登陆失败
    ctx.body = {
      code: 500,
      msg: '账号或密码错误'
    }
  }
})

// 重新登陆
router.get('/:uid/relogin', async function (ctx, next) {
  let { stu, passwd } = ctx.request.query
  let { uid } = ctx.params;


  let ehallAgent = await userLogin.ehallLogin(stu, passwd)
  let webvpnAgent = await userLogin.webvpnLogin(stu, passwd)

  if (ehallAgent && webvpnAgent) {
    AgentMap.set(uid, { stu: stu, ehall: ehallAgent, webvpn: webvpnAgent })
    ctx.body = {
      code: 200,
      msg: 'success'
    }
    db.updateLoginTime(uid, Date.now())
  } else {
    ctx.body = {
      code: 400,
      msg: 'Login Failed'
    }
  }

})



/**
 * @description [动态路由]用户唯一路由，访问该路由可以获取用户信息。
 */
router.get('/:uid', async (ctx, next) => {
  let { uid } = ctx.params;

  // 先查询数据库中是否有该学生信息
  let userInfo = await db.queryStuInfoByUid(uid)
  if (userInfo) {
    // 若有学生信息则先返回信息
    ctx.body = {
      code: 200,
      msg: 'success',
      data: userInfo[0]
    }
  } else {
    // 没有从数据库中获取到数据，则没有登陆，返回无效会话信息
    ctx.body = {
      code: 404,
      success: false,
      msg: '无效uid！'
    }
  }

})


async function template(uid, [{ dbQueryfn, dbQueryargs }, { infoQueryfn, AgentArgs, infoQueryargs }, { updatefn }, { insertfn }], identifys, update_identifys) {


  console.log('template start')

  // 解构agent内部参数

  // 尝试获取数据库数据
  let dbData = []
  let response = {}

  dbData = Array.from(await db[dbQueryfn](...dbQueryargs))
  // 尝试获取agent数据
  let user = AgentMap.get(uid)
  let loginStatus = Date.now() - Array.from(await db.queryLoginTime(uid))[0].logintime <= 20 * 60 * 1000 ? true : false
  let agArgs = []

  // console.log(dbData) 

  if (dbData.length > 0) {
    // 数据库存在数据 返回数据给前端
    response.code = 200
    response.msg = 'success'
    response.data = dbData
    // 开始进行数据更新，检查agent是否可用
    if (user && loginStatus) {
      response.loginStatus = true
      for (let i = 0; i < AgentArgs.length; i++) {
        agArgs.push(user[AgentArgs[i]])
      }
      // agent可用，开始数据爬取
      infoQuery[infoQueryfn](...agArgs, ...infoQueryargs).then(res => {

        let updateArray = []
        let insertArray = []
        console.log('爬取到数据内容:', res)
        res.forEach(ele => {
          let find_res = dbData.find(_e => {
            for (let i = 0; i < identifys.length; i++) {
              if (ele[identifys[i]] != _e[identifys[i]]) return false
            }
            return true
          })

          if (find_res == undefined) {
            console.log('检查到insert数据')
            insertArray.push(ele)
          } else {
            for (let i = 0; i < update_identifys.length; i++) {
              console.log('检查是否为update数据')
              console.log(find_res[update_identifys[i]], '---', ele[update_identifys[i]])
              if (find_res[update_identifys[i]] != ele[update_identifys[i]]) {
                console.log('是更新数据！')
                updateArray.push(ele)
                console.log(updateArray)
                break
              }
            }
          }
        })

        if (updateArray.length > 0) {
          updateArray.forEach(ele => {
            console.log('要更新的数据：', ele)
            db[updatefn](ele)
          })
        }
        // console.log(insertArray[0])
        if (insertArray.length > 0) {
          insertArray.forEach(async ele => {
            // console.log(ele)
            await db[insertfn](ele)
          })
        }
      })
    } else {
      // agent不可用，返回给客户端。提示客户端重新登陆
      response.loginStatus = false
    }
  } else {
    // 数据库中不存在数据
    if (user && loginStatus) {
      for (let i = 0; i < AgentArgs.length; i++) {
        agArgs.push(user[AgentArgs[i]])
      }
      // 判断agent是否有效，有效则进行数据爬取
      let r = await infoQuery[infoQueryfn](...agArgs, ...infoQueryargs)

      // 数据库数据插入
      r.map(x => {
        db[insertfn](x)
      })
      response.code = 200
      response.msg = 'success'
      response.data = r
      response.loginStatus = true
    } else {
      // 无效则返回错误信息
      response.code = 400
      response.msg = '会话失效！请重新登陆'
      response.loginStatus = false
    }
  }

  console.log('template end')
  return response
}

/**
 * @description [成绩路由]根据用户id进行成绩的获取
 */
router.get('/:uid/getScore', async (ctx, next) => {
  let { uid } = ctx.params;
  let { xn, xq } = ctx.request.query

  let response = {}
  // let user = AgentMap.get(uid)

  response = await template(uid, [{
    dbQueryfn: 'queryScore',
    dbQueryargs: [uid, xn, xq]
  }, {
    infoQueryfn: 'getScore',
    AgentArgs: ['webvpn', 'stu'],
    infoQueryargs: [xn, xq]
  }, {
    updatefn: 'updateScore'
  }, {
    insertfn: 'insertScroeInfo'
  }], ['courseid'], ['score'])




  console.log(response)
  ctx.body = response



  return
})




/**
 * 
 * @description [本周课表路由]
 */
router.get('/:uid/getToWeekSchedule', async (ctx, next) => {
  let { uid } = ctx.params;

  let { zc } = ctx

  template(uid, [
    {
      dbQueryfn: 'queryToWeekSchedule',
      dbQueryargs: uid, zc
    }
  ])

  let user = AgentMap.get(uid)

  // console.log(user);
  if (user) {
    let agent = user.ehall

    let toDay = await infoQuery.getTodayInfo(agent)

    let toWeekSchedule = await infoQuery.getScheduleByWeek(agent, toDay)

    toWeekSchedule.code = 200

    ctx.body = toWeekSchedule
  } else {
    ctx.body = {
      code: 404,
      msg: '会话失效！请重新获取uid'
    }
  }
})



/**
 * 
 * @description [通过周次信息获取课程信息]
 */
router.get('/:uid/getSchedule', async (ctx, next) => {
  let { uid } = ctx.params;

  let { xn, xq, zc } = ctx.request.query

  console.log(xn, xq, zc)
  let response = await template(uid, [
    {
      dbQueryfn: 'querySchedule',
      dbQueryargs: [uid, xn, xq, zc]
    }, {
      infoQueryfn: 'getScheduleByWeek',
      AgentArgs: ['ehall', 'stu'],
      infoQueryargs: [xn, xq, zc]
    }, {
      updatefn: 'updateSchedule'
    }, {
      insertfn: 'insertSchedule'
    }
  ], ['courseid'], [])

  ctx.body = response
})



/**
 * 
 * @description [获取今日信息]
 */
router.get('/:uid/getTodayInfo', async (ctx, next) => {
  let { uid } = ctx.params;

  let user = AgentMap.get(uid)
  if (user) {
    let agent = user.ehall
    let toDay = await infoQuery.getTodayInfo(agent)
    // console.log(toDay);
    ctx.body = {
      code: 200,
      msg: 'success',
      data: toDay
    }
  } else {
    ctx.body = {
      code: 404,
      msg: '会话失效！请重新获取uid'
    }
  }
})


/**
 * 
 * @description [获取电费路由]
 */
router.get('/:uid/getPowerRate', async (ctx, next) => {

  let { uid } = ctx.params;
  let response = await template(uid, [{
    dbQueryfn: 'queryPowerRate',
    dbQueryargs: [uid]
  }, {
    infoQueryfn: 'getPowerRate',
    AgentArgs: ['ehall', 'stu'],
    infoQueryargs: []
  }, {
    updatefn: 'updatePowerRate'
  },
  {
    insertfn: 'insertPowerate'
  }],
    ['sno'], ['powerrate'])


  console.log(response);
  ctx.body = response


})



/**
 * 
 * @description [一卡通费用接口]
 */
router.get('/:uid/getEcard', async function (ctx, next) {
  let { uid } = ctx.params;


  let agent = superagent.agent()

  let response = await template(uid, [
    {
      dbQueryfn: 'queryEcard',
      dbQueryargs: [uid]
    }, {
      infoQueryfn: 'getEcard',
      AgentArgs: ['stu'],
      infoQueryargs: [agent]
    }, {
      updatefn: 'updateEcard'
    },
    {
      insertfn: 'insertEcard'
    }
  ], ['sno'], ['ecard'])


  ctx.body = response


})

module.exports = router
